#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <sstream>
#include <iostream>
#include <vector>
#include <string>
#include <iomanip>
#include <sys/wait.h>
#include <map>
#include <algorithm>

#include "../logServer/clogger.h"
#include "wifiApi.h"
#include "wifiMsgHandle.h"
#include "common.h"

#define WIFILogDebug(fmt, args...) CLogger(MODULE_WIFI, __FILE__, __LINE__, LOG_DEBUG, fmt, ##args);
#define WIFILogInfo(fmt, args...) CLogger(MODULE_WIFI, __FILE__, __LINE__, LOG_INFO, fmt, ##args);
#define WIFILogNotice(fmt, args...) CLogger(MODULE_WIFI, __FILE__, __LINE__, LOG_NOTICE, fmt, ##args);
#define WIFILogWarning(fmt, args...) CLogger(MODULE_WIFI, __FILE__, __LINE__, LOG_WARNING, fmt, ##args);
#define WIFILogError(fmt, args...) CLogger(MODULE_WIFI, __FILE__, __LINE__, LOG_ERR, fmt, ##args);
#define WIFILogCrit(fmt, args...) CLogger(MODULE_WIFI, __FILE__, __LINE__, LOG_CRIT, fmt, ##args);
#define WIFILogAlert(fmt, args...) CLogger(MODULE_WIFI, __FILE__, __LINE__, LOG_ALERT, fmt, ##args);
#define WIFILogEmerg(fmt, args...) CLogger(MODULE_WIFI, __FILE__, __LINE__, LOG_EMERG, fmt, ##args);

#define WIFI_DEBUG  1
#define WIFI_SLOT   12

using namespace std;

//WIFI module state
const char *WIFIStatesStr[(int)WIFI_MODULE_NSYNC+1] =
{
    "Idle",
    "Configuring",
    "Configured",
    "Restarting",
    "Running",
    "Shutdown",
    "OOS"
};

//some runtime information
wifiModuleState_t           gWifiState;               /* global WIFI module state */
pthread_mutex_t             WIFIMutex;                /* for modify cdma baseband state between two thread */
time_t                      wifiCurTime;              /* current time counter since from 1970 */

U32           wifiFilterTime = 30 * 60;               /* for filter wifi duplicate mac */

MODREG modWIFIInfo = {MODULE_WIFI, true, true, TICK_INTERVAL, (char *)"WIFI"};

//communication address
sockaddr_in        WIFIRemoteAddr;
sockaddr_in        WIFILocalAddr;
conn_context       WIFI_tcp_ctxt;
conn_t*            WIFI_tcp_conn_t = NULL;

#define WIFI_HAERTBEAT_INTERVAL       5000
void*   pWIFIHeartBeatTimer = NULL;
void    handleWIFIHeartBeatTimer(void *h);

#define WIFI_CLEAN_DATA_INTERVAL      (1000 * 30 * 60) //30 min
void*   pWIFICleanDataTimer = NULL;
void    handleCleanDataTimer(void *h);

//module init function
bool WIFIModuleInit();
void WIFI_tlv_msg_handler();
bool initWIFIInternalMsgTask();
bool initWIFITcpMsgTask();
bool isToReport(std::string& macAddr, time_t& currTime);
/*
 *******************************************************************************
 *            common function definition
 *
 ******************************************************************************* 
*/
static void handle_WIFI_tcp_message(struct conn_t* c, const char* buf, ssize_t len);
static void on_close(struct conn_t* c);
static void on_error(struct conn_t* c);
static struct conn_cb_t tcp_callback = {
       handle_WIFI_tcp_message,
       on_close,
       on_error
};


void setdevtimestr(char * str);
wifiModuleState_t getWIFIModuleState();
void setWIFIModuleState(wifiModuleState_t state);
bool init_WIFI_tcp_context(sockaddr_in *remote_addr, sockaddr_in* local_addr);

/******************************************************************************/
/*            tlv relate function                                             */
/******************************************************************************/
void handleWIFITlvTimeTick();
void handleWIFITlvCmdMsg(MSGHEADER *msgHdr, U8 *payload);
void handleWIFITlvCmdSetMsg(MSGHEADER *msgHdr, PCMDHEADER pCmd);
void handleWIFITlvCmdGetMsg(MSGHEADER *msgHdr, PCMDHEADER pCmd);
void handleWIFITlvCmdEventMsg(MSGHEADER *msgHdr, PCMDHEADER pCmd);
void handleWIFITlvCtrlRestartMsg(MSGHEADER *msgHdr, PCMDHEADER pCmd);
void handleWIFITlvCtrlWirelessOffMsg(MSGHEADER *msgHdr, PCMDHEADER pCmd);
void handleWIFITlvCtrlWirelessOnMsg(MSGHEADER *msgHdr, PCMDHEADER pCmd);
void handleWIFITlvCtrlWirelessCfg(MSGHEADER *msgHdr, PCMDHEADER pCmd);
void buildAndReportWIFIModuleStatus(MSGHEADER *msgHdr, PCMDHEADER pCmd);
bool buildAndSendWIFITlvCmdSetResponseMsg(MSGHEADER *msgHdr, PCMDHEADER pCmd, U32 result, U32 paraType, U32 paraValue);

//kismet message related hanlder
int setup_kismet_protocols(const char* line, ssize_t len, conn_t *tcpCon);
int handle_line_message(const char* line, ssize_t len, conn_t *tcpCon);
int handle_ssid_message(const char* line, ssize_t len, conn_t *tcpCon);
int handle_time_message(const char* line, ssize_t len, conn_t *tcpCon);
int handle_client_message(const char* line, ssize_t len, conn_t *tcpCon);
int handle_bssid_message(const char* line, ssize_t len, conn_t *tcpCon);
int resolve_kismet_message_handler(const char* data, ssize_t len, conn_t *tcpCon);

//kismet message handler
HANDLER handlers[]=
{   
    {NULL, "*PROTOCOLS: ", setup_kismet_protocols},
    {NULL, "*KISMET: ", setup_kismet_protocols},    
    {NULL, "*TIME: ", handle_time_message},
    {"!0 ENABLE CLIENT *\n", "*CLIENT: ", handle_client_message},
    {"!0 ENABLE SSID *\n", "*SSID: ", handle_ssid_message},
    {"!0 ENABLE STATUS *\n", "*STATUS: ", NULL},
    {"!0 ENABLE BSSID *\n", "*BSSID: ", handle_bssid_message},
    {NULL, "", handle_line_message}
};

inline time_t getWIFICurrentTime()
{
    return wifiCurTime;
}

inline void setWIFICurrentTime()
{
    wifiCurTime = time(NULL);
}

inline void increaseWIFICurrentTime(int tick)
{
    wifiCurTime += tick;
}

// i.e. after the duration, if the UE enter the eNodeB again, it will be reported again.
std::map<std::string, uint64_t> macAddrFilterHistoryMap_m;
bool isToReport(std::string& macAddr, time_t& currTime)
{
    uint64_t newTime = (uint64_t)currTime; 
    // if not buffered, always do NOT hold it, no matter filter enabled or not.
    std::map<std::string, uint64_t>::iterator it = macAddrFilterHistoryMap_m.find(macAddr);
    if (it == macAddrFilterHistoryMap_m.end()) 
    {
        macAddrFilterHistoryMap_m[macAddr] = newTime;  
        WIFILogDebug("isToReport(): MACADDR[%s] is NOT buffered yet, report it", macAddr.c_str());
        return true;
    }
    else
    {
        if ((newTime - it->second) > wifiFilterTime)
        {
            WIFILogDebug("isToReport(): more than %d seconds passed "
                    "after last report of MACADDR[%s], report it(current timestamp[%llu],"
                    "last report timestamp[%llu])",
                    wifiFilterTime,
                    macAddr.c_str(),
                    newTime,
                    it->second);
            
            macAddrFilterHistoryMap_m[macAddr] = newTime;         
            return true;
        }
        else
        {
            WIFILogDebug("isToReport(): less than %d seconds passed "
                         "after last report of MACADDR[%s], hold it,(current timestamp[%llu],"
                         " last report timestamp[%llu])",
                         wifiFilterTime,
                         macAddr.c_str(),
                         newTime,
                         it->second);
            return false;
        }
    }
}

void startKismetServer()
{
    //start kismet server
    pid_t fpid = fork();
    signal(SIGCHLD, SIG_IGN);    
    if( fpid==0 )
    {
        execlp("kismet_server", "kismet_server", "-c", "wlan0", "-s", "--daemonize", "-n", "--no-logging", NULL);
    }
    else if( fpid<0 )
    {
        WIFILogCrit("Error in fork");
        setWIFIModuleState(WIFI_MODULE_SHUTDOWN);
        return;
    }
    else
    {
        WIFILogNotice("Fork child[%d] to start kesmet server", fpid);
    }

    setWIFIModuleState(WIFI_MODULE_RUNNING);
}

static void closeWifiSession(void)
{    
    WIFILogNotice("System is exiting, closing wifi socket.");
    release_connection(WIFI_tcp_conn_t);
}

/**
 ****************************************************************************************
 * Set devtimestr, time is string  
 ****************************************************************************************
 */
void setwifidevtimestr(char *str)
{
    time_t   now;
    struct   tm  *timenow;

    /* 1. get system time */
    now = getWIFICurrentTime();
    timenow = localtime(&now);
    char s[15];
    strftime(s, sizeof(s), "%Y%m%d%H%M%S", timenow);
    WIFILogDebug( "time:%s", s);
    memcpy(str, s, sizeof(s));
    WIFILogDebug( "DEVTIMESTR:%s",str);
}

void WIFI_tlv_msg_handler()
{
    MSGHEADER msgHdr;
    U8 payload[MAX_MSG_SIZE];
      
    while(1)
    {
        if( MSG_read(MODULE_WIFI, &msgHdr, (void *)payload) != 0 )
        {
            //dbgprintf(DEBUG_ERROR, stderr, "internal_msg_thread:MSG_read error. \n");
            continue;
        }
    
        if( MODULE_WIFI != msgHdr.dstID )
        {
            WIFILogError("received a wrong tlv msg id = %d ", msgHdr.dstID);
            continue;
        }
        
        WIFILogDebug("received tlv msg id = %d ", msgHdr.srcID);
        switch ( msgHdr.msgType )
        {
            case MSG_TYPE_COMMAND:
                handleWIFITlvCmdMsg(&msgHdr, payload);
                break;
            case MSG_TYPE_TICK:
                handleWIFITlvTimeTick();
                break;
            default:
              WIFILogError("Unknown msg type %x\n ", msgHdr.msgType);
              break;
        }
    }
}

bool WIFIModuleInit()
{
    //1. init global parameter
    gWifiState = WIFI_MODULE_IDLE;
    
    //2. register module
    if( RC_OK != MOD_register(&modWIFIInfo) )
    {
        WIFILogError("can't register WIFI module with syscore\n");
        return false;
    }

    //set system time
    setWIFICurrentTime();

    return true;
}

//
RESULT WIFI_init(void)
{
    //1. WIFI module initialization
    if( !WIFIModuleInit() )
    {   
        WIFILogError("WIFI module initialization failed. \n");
        return RC_FAIL; 
    }

    //2. create internal msg handler thread 
    if( !initWIFIInternalMsgTask() )
    {
        WIFILogError("Can't create WIFIInternalMsgtask thread. \n");
        return RC_FAIL;
    }

    //3. create tcp msg handler thread 
    if( !initWIFITcpMsgTask() )
    {
        WIFILogError("Can't create WIFIUdpMsgTask thread. \n");
        return RC_FAIL;
    }

    return RC_OK;
}

static void* WIFI_internal_task_thread(void *arg __attribute__((unused)))
{
    pthread_setname_np(pthread_self(), "wifiinternal");
    pWIFIHeartBeatTimer = MOD_timerStart(MODULE_WIFI, WIFI_HAERTBEAT_INTERVAL, handleWIFIHeartBeatTimer, NULL);

    pWIFICleanDataTimer = MOD_timerStart(MODULE_WIFI, WIFI_CLEAN_DATA_INTERVAL, handleCleanDataTimer, NULL);

    atexit(closeWifiSession);

    //start to handle message from other module
    WIFI_tlv_msg_handler();

    WIFILogError("Exiting the WIFI_internal_task_thread thread\n");
    pthread_exit( (void*)0 );
}

bool initWIFIInternalMsgTask()
{
    pthread_t       thread;

    if(pthread_create(&thread, NULL, WIFI_internal_task_thread, NULL) != RC_OK)
    {
        return false;
    }

    return true;
}



/****************************************************************************************/
/*           tlv relate function                                                        */
/****************************************************************************************/
/****************************************************************************************/
/*           Handle time tick from dispatcher module                                    */
/****************************************************************************************/
void handleWIFITlvTimeTick()
{
    increaseWIFICurrentTime(TICK_SECOND);
    MOD_timerProc(MODULE_WIFI);
}
 
void handleWIFITlvCmdMsg(MSGHEADER *msgHdr, U8 *payload)
{
    PCMDHEADER pCmd = (PCMDHEADER) payload;

    switch (pCmd->cmdType)
    {
        case CMD_SET:
            handleWIFITlvCmdSetMsg(msgHdr, pCmd);
            break;
        case CMD_GET:
            handleWIFITlvCmdGetMsg(msgHdr, pCmd);
            break;
        case CMD_EVENT:
            handleWIFITlvCmdEventMsg(msgHdr, pCmd); 
            break;
        default:
            WIFILogWarning("Unknown CmdType = %x",  pCmd->cmdType);
            break;
    }
}

void handleWIFITlvCmdEventMsg(MSGHEADER *msgHdr, PCMDHEADER pCmd)
{
    switch (pCmd->cmdCode)
    {
        case CMD_CODE_SYS_EXIT: 
            WIFILogError("system is exiting, closing WIFI socket. \n");
            release_connection(WIFI_tcp_conn_t);
            break;
        case CMD_CODE_SYS_TIME_SYNC:
            WIFILogNotice("system set current time");
            setWIFICurrentTime();
            break;
        default:
            WIFILogNotice("Unknown cmdCode = %x \n", pCmd->cmdCode);        
            break;
    }
}

void handleWIFITlvCmdSetMsg(MSGHEADER *msgHdr, PCMDHEADER pCmd)
{
    switch (pCmd->cmdCode)
    {
        case CMD_WIFI_RESTART:
            handleWIFITlvCtrlRestartMsg(msgHdr, pCmd);
            break;
        case CMD_WIFI_WIRELESS_OFF:
            handleWIFITlvCtrlWirelessOffMsg(msgHdr, pCmd);
            break;
        case CMD_WIFI_WIRELESS_ON:
            handleWIFITlvCtrlWirelessOnMsg(msgHdr, pCmd);
            break;
        case CMD_WIFI_CFG_WIRELESS: 
            handleWIFITlvCtrlWirelessCfg(msgHdr, pCmd);
            break;     
        default:
            WIFILogWarning("Unknown cmdCode = %x \n", pCmd->cmdCode);
            break;
    }
}

void handleWIFITlvCmdGetMsg(MSGHEADER *msgHdr, PCMDHEADER pCmd)
{
    switch (pCmd->cmdCode)
    {   
        case CMD_WIFI_GET_MODULE_STATUS:
            buildAndReportWIFIModuleStatus(msgHdr, pCmd);
            break;
        default:
          WIFILogWarning("Unknown cmdCode = %x \n",  pCmd->cmdCode);
          break;
    }       
}

void handleWIFITlvCtrlWirelessOffMsg(MSGHEADER *msgHdr, PCMDHEADER pCmd)
{
    buildAndSendWIFITlvCmdSetResponseMsg(msgHdr, pCmd, PARA_VALUE_RESULT_SUCCESS, 0, 0);
	system("killall -9 kismet_server");
    setWIFIModuleState(WIFI_MODULE_SHUTDOWN);
}

void handleWIFITlvCtrlWirelessOnMsg(MSGHEADER *msgHdr, PCMDHEADER pCmd)
{
    buildAndSendWIFITlvCmdSetResponseMsg(msgHdr, pCmd, PARA_VALUE_RESULT_SUCCESS, 0, 0);
    setWIFIModuleState(WIFI_MODULE_RUNNING);
}

void handleWIFITlvCtrlRestartMsg(MSGHEADER *msgHdr, PCMDHEADER pCmd)
{
    buildAndSendWIFITlvCmdSetResponseMsg(msgHdr, pCmd, PARA_VALUE_RESULT_SUCCESS, 0, 0);
    setWIFIModuleState(WIFI_MODULE_RUNNING);
}

void handleWIFITlvCtrlWirelessCfg(MSGHEADER *msgHdr, PCMDHEADER pCmd)
{
    PPARAM pParam =(PPARAM)(pCmd+1);
    U32 len = pCmd->cmdLength;
    U32 paraType;
    U32 paraLength;
    U8* paraValue;
    UNPACK_RESULT uprc; 

    while((uprc=CM_paraUnpackPara(&pParam, &len, &paraType, &paraLength,&paraValue)) == UNPACK_OK)
    {
        switch(paraType)
        {
            case PARA_TYPE_WIFI_RECAPT_TIME:
                wifiFilterTime = *((U32 *)paraValue) * 60;
                break;
            default:
                WIFILogError("Unknown paramType error in received cmdcode = %x",   pCmd->cmdCode);
                buildAndSendWIFITlvCmdSetResponseMsg(msgHdr, pCmd, PARA_VALUE_RESULT_FAILED, PARA_TYPE_ERROR_CODE, PARA_VALUE_ERROR_UNKNOWN_PARATYPE);
                break;
        }
    }

    if( uprc == UNPACK_ERROR )
    {
        WIFILogError("Parameter unpack error in received cmdcode = %x", pCmd->cmdCode);

        buildAndSendWIFITlvCmdSetResponseMsg(msgHdr, pCmd, PARA_VALUE_RESULT_FAILED, PARA_TYPE_ERROR_CODE, PARA_VALUE_ERROR_ILLEGAL_PARA_STRUCT);
        
        return;
    }

    if(getWIFIModuleState() == WIFI_MODULE_IDLE)
    {
        if ( getPidByName((char *)"kismet_server") )
        {
            WIFILogDebug("kismet server is active"); 
        }
        else
        {
            signal(SIGCHLD, SIG_IGN);            
            //start kismet server
            pid_t fpid = fork();
            if( fpid == 0 )
            {
                execlp("kismet_server", "kismet_server", "-c", "wlan0", "-s", "--daemonize", "-n", "--no-logging", NULL);
            }
            else if( fpid < 0 )
            {
                buildAndSendWIFITlvCmdSetResponseMsg(msgHdr, pCmd, PARA_VALUE_RESULT_FAILED, 0, 0);     
                WIFILogCrit("Error in fork");
                return;
            }
            else
            {
                WIFILogNotice("Fork child[%d] to start kesmet server", fpid);
            }
        }
    }

    buildAndSendWIFITlvCmdSetResponseMsg(msgHdr, pCmd, PARA_VALUE_RESULT_SUCCESS, 0, 0);
    setWIFIModuleState(WIFI_MODULE_RUNNING);
}

void checkKismetServer()
{
    if ( getWIFIModuleState() !=  WIFI_MODULE_IDLE )
    {
        if ( getPidByName((char *)"kismet_server") )
        {
            WIFILogDebug("kismet server is active"); 
        }
        else
        {
            WIFILogWarning("kismet server is deactive restart kismet server");
            startKismetServer();

            sleep(5);
            if ( !init_WIFI_tcp_context(&WIFIRemoteAddr, &WIFILocalAddr))
            {
                WIFILogWarning("can not re-connect kismet server");
            }
            else
            {
                WIFILogNotice("re-connect kismet server success");
            }
        }
    }
}


void handleWIFIHeartBeatTimer(void *h)
{
    U32 rc = PARA_VALUE_SYSMONITOR_MODULE_OK;
    CM_SendMsg_1Para(MODULE_SYSMONITOR, MODULE_WIFI, MSG_TYPE_COMMAND, CMD_EVENT, CMD_CODE_SYSMONITOR_HEARTBEAT, 0,
        PARA_TYPE_SYSMONITOR_MODULE_STATE,sizeof(U32), (U8*)&rc);   
    checkKismetServer();
    MOD_timerRestart(pWIFIHeartBeatTimer, WIFI_HAERTBEAT_INTERVAL);
}

void handleCleanDataTimer(void *h)
{
    std::map<std::string, uint64_t>::iterator it;
    for (it=macAddrFilterHistoryMap_m.begin(); it!=macAddrFilterHistoryMap_m.end(); it++)
    {
        if (it->second + wifiFilterTime < (uint64_t)wifiCurTime)
        {
            macAddrFilterHistoryMap_m.erase(it);
        }
    }
    
    MOD_timerRestart(pWIFICleanDataTimer, wifiFilterTime * 1000);
}

/**
 ****************************************************************************************
 * @brief   build and send cmd set response to dispatcher module, 
 * @param   result            -  failed or success
 * @return  none
 ****************************************************************************************
 */ 
bool buildAndSendWIFITlvCmdSetResponseMsg(MSGHEADER *msgHdr, PCMDHEADER pCmd, U32 result, U32 paraType, U32 paraValue)
{
    U8 cmdResponse = (pCmd->cmdType & 0xf) | 0x10;
   
    if(result == PARA_VALUE_RESULT_FAILED)
    {
        CM_SendMsg_2Para(msgHdr->srcID, MODULE_WIFI, MSG_TYPE_COMMAND, cmdResponse, pCmd->cmdCode, pCmd->cmdIndex,
                         PARA_TYPE_RESULT, 4, (U8 *)&result, paraType, 4, (U8 *)&paraValue);
    }
    else
    {
        CM_SendMsg_1Para(msgHdr->srcID, MODULE_WIFI, MSG_TYPE_COMMAND, cmdResponse, pCmd->cmdCode, pCmd->cmdIndex,
                         PARA_TYPE_RESULT, 4, (U8 *)&result);
    }

    return true;
}


/**
 ****************************************************************************************
 * @brief   build and report WIFI module status, 
 * @return  none
 ****************************************************************************************
 */
void buildAndReportWIFIModuleStatus(MSGHEADER *msgHdr, PCMDHEADER pCmd)
{
    wifiModuleState_t state = getWIFIModuleState();
    U32  msgLength = strlen(WIFIStatesStr[state]);

    CM_SendMsg_1Para(msgHdr->srcID, MODULE_WIFI,MSG_TYPE_COMMAND, CMD_GET_RESPONSE, pCmd->cmdCode, pCmd->cmdIndex,
                     PARA_TYPE_WIFI_MODULE_STATUS, msgLength, (U8 *)WIFIStatesStr[state]);
}

wifiModuleState_t getWIFIModuleState()
{
    wifiModuleState_t state;

    pthread_mutex_lock(&WIFIMutex);    
    state = gWifiState;
    pthread_mutex_unlock(&WIFIMutex);

    WIFILogDebug("Get WIFI module state: %s", WIFIStatesStr[state]);

    return state;
}

void setWIFIModuleState(wifiModuleState_t state)
{
    pthread_mutex_lock(&WIFIMutex);    
    gWifiState = state;
    pthread_mutex_unlock(&WIFIMutex);

    WIFILogDebug("Set WIFI module state: %s", WIFIStatesStr[state]);
}

void handleWIFIloadMAC(const char* buf, ssize_t len)
{
    RESULT rc = RC_MOD_INVALID;
    //U64 ctime = getWIFICurrentTime();
	U64 ctime = time(NULL);
	U8 mac[20] = {0};

    memcpy(mac, buf, len);
    
    WIFILogDebug("time= %llu  mac = %s",  ctime, (char *)mac);

    rc = CM_SendMsg_2Para(MODULE_DATAPRO, MODULE_WIFI,MSG_TYPE_INTERNAL, CMD_EVENT, CMD_EVT_WIFI_MAC, 0, 
                          PARA_TYPE_EUTRAN_TIME, 8, (U8 *)&ctime, 
                          PARA_TYPE_WIFI_MAC_REPORT, 12, (U8 *)mac);
}

/*
 * callback func to handle message from kismet server.
 */

int setup_kismet_protocols(const char* line, ssize_t len, conn_t *tcpCon)
{
    unsigned i;
    WIFILogNotice("Enabling protocols\n");
    
    for(i=0;i<sizeof(handlers)/sizeof(HANDLER);i++)
    {
        if(handlers[i].enable)
        {
            send_msg(tcpCon, handlers[i].enable, strlen(handlers[i].enable));       
        }
    }

    return 0;
}

int handle_line_message(const char* data, ssize_t len, conn_t *tcpCon)
{
    WIFILogDebug("DATA %d: %s\n", (int)strlen(data), data);
    return 0;
}

int handle_client_message(const char* data, ssize_t len, conn_t *tcpCon)
{   
    WIFILogDebug("%s\n", data);
    int iPos = 0;

    std::string mac;
    std::string recvBuf;
    recvBuf.append(data, len);

    if( recvBuf.length() < 4)
    {
        return -1;
    }

    while( WIFI_MAC_MSG_LENGTH <=recvBuf.length() )
    {   
        iPos = recvBuf.find(WIFI_MSG_CLIENT, 0);

        if(iPos == -1) break;

        recvBuf.erase(0, iPos + WIFI_CLIENT_LENGTH);

        if(recvBuf.length() < MAC_ID_LENGTH) 
            break;

        mac = recvBuf.substr(0, MAC_ID_LENGTH);
        if (isToReport(mac, wifiCurTime))
        {
           mac.erase(std::remove(mac.begin(), mac.end(), ':'), mac.end());
           
           handleWIFIloadMAC(mac.c_str(), mac.length());
        }
        
        recvBuf.erase(0, MAC_ID_LENGTH);
    }
    
    return 0;
}

int handle_ssid_message(const char* data, ssize_t len, conn_t *tcpCon)
{   
    WIFILogDebug("%s\n", data);
    int iPos = 0; 

    std::string mac;
    std::string recvBuf;
    recvBuf.append(data, len);

    if( recvBuf.length() < 4)
    {
        return -1;
    }

    while( WIFI_MAC_MSG_LENGTH <=recvBuf.length() )
    {   
        iPos = recvBuf.find(WIFI_MSG_SSID, 0);

        if(iPos == -1) break;

        recvBuf.erase(0, iPos + WIFI_SSID_LENGTH);

        if(recvBuf.length() < MAC_ID_LENGTH) 
            break;

        mac = recvBuf.substr(0, MAC_ID_LENGTH);
        if (isToReport(mac, wifiCurTime))
        {
           mac.erase(std::remove(mac.begin(), mac.end(), ':'), mac.end());
           handleWIFIloadMAC(mac.c_str(), mac.length());
        }
        
        recvBuf.erase(0, MAC_ID_LENGTH);
    }
    
    return 0;
}

int handle_bssid_message(const char* data, ssize_t len, conn_t *tcpCon)
{   
    WIFILogDebug("%s\n", data);
    int iPos = 0; 

    std::string mac;
    std::string recvBuf;
    recvBuf.append(data, len);

    if( recvBuf.length() < 4)
    {
        return -1;
    }

    while( WIFI_MAC_MSG_LENGTH <= recvBuf.length() )
    {   
        iPos = recvBuf.find(WIFI_MSG_BSSID, 0);

        if(iPos == -1) break;

        recvBuf.erase(0, iPos + WIFI_BSSID_LENGTH);

        if(recvBuf.length() < MAC_ID_LENGTH)
            break;

        mac = recvBuf.substr(0, MAC_ID_LENGTH);
        if (isToReport(mac, wifiCurTime))
        {
           mac.erase(std::remove(mac.begin(), mac.end(), ':'), mac.end());
           handleWIFIloadMAC(mac.c_str(), mac.length());
        }
        
        recvBuf.erase(0, MAC_ID_LENGTH);
    }
    
    return 0;
}


int handle_time_message(const char* data, ssize_t len, conn_t *tcpCon)
{   
    WIFILogDebug("TIME: %s\n",data);        
    return 0;
}

int resolve_kismet_message_handler(const char* data, ssize_t len, conn_t *tcpCon)
{
    unsigned i; 
    for(i=0; i < sizeof(handlers)/sizeof(HANDLER); i++)
    {
        if(handlers[i].header)
        {
            if(!strncmp(data, handlers[i].header, strlen(handlers[i].header)))
            {
                if(handlers[i].handler)
                {
                    return handlers[i].handler(data, len, tcpCon);
                }
                else
                {
                    return 0;               
                }
            }
        }
    }
    
    WIFILogNotice("No handler found for line: %s\n", data); 

    return -1;
}

/*
 * callback func to handle message of a UDP connection.
 */
static void handle_WIFI_tcp_message(struct conn_t* c, const char* buf, ssize_t len)
{
    resolve_kismet_message_handler(buf, len, WIFI_tcp_conn_t);
}

static void on_close(struct conn_t* c)
{
    WIFILogError("kismet connection closed.");
    
    if (c != NULL)
    { 
        release_connection(c);
    }

    setWIFIModuleState(WIFI_MODULE_SHUTDOWN);
    return; 
}

static void on_error(struct conn_t* c)
{
    if(errno == EINTR) return;

    WIFILogError("kismet fata error hapened. errno = %d", errno);

    if ( c!= NULL )
    {  
        release_connection(c);
    }

    setWIFIModuleState(WIFI_MODULE_SHUTDOWN);

    return;
}

bool init_WIFI_tcp_context(sockaddr_in *remote_addr, sockaddr_in* local_addr)
{
    conn_context_init(&WIFI_tcp_ctxt);

    /*
     * make a udp connecton to a remote peer 
     */
    WIFI_tcp_conn_t = make_tcpconn_to(&WIFI_tcp_ctxt, remote_addr, &tcp_callback);

    if(WIFI_tcp_conn_t == NULL)
    {
        WIFILogError("tcp connect error");
        return false;
    }

    return true;
}

static void* WIFI_tcp_task_thread(void *arg __attribute__((unused)))
{
    WIFILogNotice("WIFI_tcp_task_thread thread id is %lu \n", pthread_self()); 
    pthread_setname_np(pthread_self(), "wifitcptask");

    //init udp context
#if 0    
        WIFILocalAddr.sin_addr.s_addr = inet_addr(WIFI_MODULE_IP);
        WIFILocalAddr.sin_port = htons(atoi(WIFI_MODULE_PORT));
        WIFILocalAddr.sin_family = AF_INET;
#endif
    WIFIRemoteAddr.sin_addr.s_addr = inet_addr(WIFI_OUR_BOARD_IP);
    WIFIRemoteAddr.sin_port = htons(atoi(WIFI_OUR_BOARD_PORT));
    WIFIRemoteAddr.sin_family = AF_INET;

    //when status is running, then start to connect kismet_server
    while(1)
    {
        if(getWIFIModuleState() == WIFI_MODULE_RUNNING)
        { 
            //wait kismet_server start totally
            sleep(10);
            if(!init_WIFI_tcp_context(&WIFIRemoteAddr, &WIFILocalAddr) )
            {
                WIFILogWarning("fail to init tcp connection context.\n");
                sleep(5);
                continue;
            }

            break;
        }
        
        sleep(2);
    }

    //start main loop to handle network messasge
    main_loop(&WIFI_tcp_ctxt);

    WIFILogWarning("Exiting the WIFI_udp_task_thread thread\n");
    pthread_exit( (void*)0 );
}

bool initWIFITcpMsgTask()
{
    pthread_t       thread;
    pthread_attr_t  attr;
    struct sched_param sched;
    int32_t minAllowedPrio, maxAllowedPrio;
    int32_t schedPolicy = SCHED_OTHER;
    int32_t schedPriority = 0;

    if( pthread_attr_init(&attr) )
    {
        WIFILogError("pthread_attr_init failed : %s\n", strerror(errno));
        return false;
    }

    if( pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) )
    {
        WIFILogError("pthread_attr_setinheritsched failed : %s\n", strerror(errno));
        return false;
    }

    if( pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) )
    {
        WIFILogError("pthread_attr_setdetachstate failed: %s\n", strerror(errno));
        return false;
    }

    /****************** Setup scheduling **************************/
    /* If we are not superuser, don't try changing scheduling */
    if( (getuid() != 0) && (schedPolicy != SCHED_OTHER) )
    {
        WIFILogError("Don't have permission for ttisched != OTHER\n");
        return false;
    }

    if( schedPolicy == SCHED_OTHER && schedPriority != 0 )
    {
        WIFILogError("maxp %d invalid for ttisched OTHER (must be 0)\n", schedPriority);
        return false;
    }

    if( (minAllowedPrio = sched_get_priority_min(schedPolicy)) < 0 )
    {
        WIFILogError("sched_get_priority_min failed : %s\n", strerror(errno));
        return false;
    }

    if( (maxAllowedPrio = sched_get_priority_max(schedPolicy)) < 0)
    {
        WIFILogError("sched_get_priority_max failed : %s\n", strerror(errno));
        return false;
    }

    if( schedPriority > maxAllowedPrio )
    {
        WIFILogError("xp %d greater than max allowed for ttisched, %d\n", schedPriority, maxAllowedPrio);
        return false;
    }

    if( schedPriority < minAllowedPrio )
    {
        WIFILogError("maxp %d lower than min allowed for ttisched, %d\n", schedPriority, minAllowedPrio);
        return false;
    }

    if( pthread_attr_setschedpolicy(&attr,schedPolicy) )
    {
        WIFILogError("pthread_attr_setschedpolicy failed: %s\n", strerror(errno));
        return false;
    }

    // Get the scheduling-parameters portion of the attr structure initialized
    // via pthread_attr_init() above
    if( pthread_attr_getschedparam(&attr, &sched) )
    {
        WIFILogError("pthread_attr_getschedparam failed : %s\n", strerror(errno));
        return false;
    }
    // Update the priority with the value passed in
    sched.sched_priority = schedPriority;
    // Update the priority in the attr structure
    if( pthread_attr_setschedparam(&attr, &sched) )
    {
        WIFILogError("pthread_attr_setschedparam failed : %s\n", strerror(errno));
        return false;
    }

    if( pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) )
    {
        WIFILogError("pthread_attr_setscope failed : %s\n", strerror(errno));
        return false;
    }

    WIFILogNotice("begin to create WIFI_udp_task_thread \n");
    if( pthread_create(&thread, &attr, WIFI_tcp_task_thread, 0) )
    {
        WIFILogError("pthread_create WIFIUdptask thread failed: %s\n", strerror(errno));
        return false;
    }
    
    return true;
}


